package day16.xianchengdemo.xianchengsafety;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Solve
{

    public static void main(String[] args)
    {

//        if(sum==10)
//        {
//            System.out.println(Thread.currentThread().getName()+"取钱成功吐出了10元");
//            demo1.sum-=10;
//            System.out.println("主线程余额扣除成功"+sum);
//        }

        Account2 at=new Account2("at-01",10000);
        Thread t1=new MyThread2(at);
        t1.start();
        Thread t2=new MyThread2(at);
        t2.start();


        Account2 at2=new Account2("at-02",10000);
        Thread t3=new MyThread2(at2);
        t3.start();
        Thread t4=new MyThread2(at2);
        t4.start();

    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Account2 //取钱，这个事情，是用户调了账户的取钱方法而已
{
    private String id;
    private  double money;


    public /*synchronized*/ void drawMoney(double money)//方法2，直接锁了这个方法，只能有一个线程进入这个方法，其他等着。如果说是成员方法锁的对象是this，如果是静态方法，那么锁的对象就是Account2.class，
    {

        //把核心代码上锁，保证做这一部分的时候，一定是让一个线程完完全全给他做完，才能让另一个线程开始做,这个锁对于访问的线程来说必须是同一个对象比如说我直接写一个字符串”。。。“,
        // 那对于这两个线程来说这个字符串常量就是唯一的在常量池中，这个锁对于他们俩线程来说就是同一个那就可以一个进一个等，只能有一把锁

                    // 对于this也就是账户类型，小明小红是调他们俩的acc账户的取钱方法，而小黑小白是调他们俩的acc2账户的取钱方法，那我这里锁限制了账户的类型，
                     //  也就是说账户类型一样就说明一个事情（同一把锁）：你就要等锁解开（另一个线程调用取钱方法执行完毕）
        synchronized (this) {
            if(this.money>=money)
            {
                System.out.println(Thread.currentThread().getName()+"成功执行："+this.money+"成功吐出了"+money);
                this.money-=money;
                System.out.println(Thread.currentThread().getName()+"取出钱之后的余额为" + this.money);
            }
            else
            {
                System.out.println(Thread.currentThread().getName()+"取钱失败余额不足");

            }
        }
    }

}

class MyThread2 extends Thread
{
    private Account2 account;

    public MyThread2(Account2 account)//地址传递，这个account记录了at的地址，传递给成员变量了
    {
        this.account = account;
    }

    public void run()//线程体，（线程要干的活），必须是void返回,判断需不需要返回值，去考虑第几种方式
    {
//            if(demo1.sum==10)
//             {
//                                    //当前实例化对象（线程）的名字，不过好像静态方法比较常用，属于类的那种
//                 System.out.println(this.getName()+"取钱成功吐出了10元");
//                 demo1.sum-=10;
//                 System.out.println("子线程余额扣除成功"+demo1.sum);
        //
        account.drawMoney(10000);
    }

}
